#include "Rectangle.h"

Rectangle::Rectangle() {
	this->posicion = new Point();
	this->base = -1;
	this->altura = -1;

}


Rectangle::~Rectangle() {
	delete(this->posicion);
}


void Rectangle::setBase(int nuevoBase) {
	base = nuevoBase;
}

int Rectangle::getBase() {
	return base;
}


void Rectangle::setAltura(int nuevoAltura) {
	altura = nuevoAltura;
}

int Rectangle::getAltura() {
	return altura;
}


void Rectangle::draw(SDL_Surface *screen) {
 
	int x = posicion->getX();;
	int y = posicion->getY();
	Stage* stage = Stage::getInstance();
    SDL_Surface * auxSurface;
	int gr;

	
	Point* resolution = stage->resolveResolution();

	int screenWidth  = resolution->getX();
	int screenHeight = resolution->getY();

	Point point1, point2, point3, point4;
	int posX = this->getPosicion()->getX();
	int posY = this->getPosicion()->getY();
	int desplazoBase = this->getBase();
	int desplazoAltura = this->getAltura();

	//Grosor de linea, primero se lo pido a la figura.
	int grosor = this->getLineThickness();
	if (grosor == -1) {
	//Si la figura no tiene grosor, se lo pido al stage.
		grosor = stage->resolveLineThickness();
		// Entonces lo levanta del stage y no entra al if que viene.
	}
	if (grosor == -1) {
	//Si ni la figura ni el stage tienen grosor, entonces lo seteo en cero,
		grosor = 0;
	}


	point1.setX(posX-grosor);
	point1.setY(posY-grosor);

	point2.setX(posX+desplazoBase+grosor);
	point2.setY(posY-grosor);

	point3.setX(posX+desplazoBase+grosor);
	point3.setY(posY+desplazoAltura+grosor);

	point4.setX(posX-grosor);
	point4.setY(posY+desplazoAltura+grosor);

	if (!isInDisplay(&point1,&point2,&point3,&point4)) {
		printf ("%s","**WARNING** La figura no se graficarÃ¡, ya que se encuentra fuera del display.\n");
		return;
	}


	if (x < 0 || y < 0){
		printf("No se dibuja la figura de id %s por no estar en area visible",getId());
		return;
	}
	
	int i;	

//	auxSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, screenWidth, screenHeight,Stage::PIXEL_THICKNESS,rBkDefault, gBkDefault, bBkDefault, 0);
   auxSurface = manager.createSurface(screenWidth,screenHeight,Stage::PIXEL_THICKNESS);


	
    gr = 0;
   	initManagerElement(gr);
	
	if ( (this->getIdTextura()) != NULL )
	{
			drawTexture(auxSurface);
	}
	else
	{
			fillColor(auxSurface);
    }
	
	//Obetner el color de linea en cascada
	int r = (this->getRColorLinea() != -1)? this->getRColorLinea() : stage->resolveLineRColor();
	int g = (this->getGColorLinea() != -1)? this->getGColorLinea() : stage->resolveLineGColor();
	int b = (this->getBColorLinea() != -1)? this->getBColorLinea() : stage->resolveLineBColor();
	manager.solveFilterColor(r,g,&b);
	manager.setColor(auxSurface,r,g,b);
    
	
	
	int thickness = (getLineThickness() != -1) ? getLineThickness() : stage->resolveLineThickness();

	for ( gr=0 ; gr<thickness ; gr++){
	
	    initManagerElement(gr);

		for (i = 0; i < 4; i++)
		{

		 setManagerElement(auxSurface,i);
		}  
	}




 	//Obtener el grosor de linea en cascada.
	 thickness = (getLineThickness() != -1) ? getLineThickness() : Stage::getInstance()->resolveLineThickness();
	//Pintamos el grosor de línea.
	this->fillThickness(auxSurface,thickness);
	
	
	
	manager.refresh(screen,auxSurface); // copia la imagen resultante a la pantalla y libera recursos
	
	
	
	


}



void Rectangle:: drawTexture(SDL_Surface *auxSurface)
{
	
	SDL_Surface * imagen;
    Transformations T;

  

	int x = posicion->getX();
	int y = posicion->getY();
	
	Stage* stage = Stage::getInstance();

    imagen = SDL_LoadBMP(stage->getTexturePath( this->getIdTextura()  ));  

	T.setScaleMatrix((double)base/(double)imagen->w,(double)altura/(double)imagen->h); // reduccion 

	SDL_LockSurface(imagen);

	manager.resizeImage(imagen,auxSurface,x,y,base,altura,T);

    SDL_UnlockSurface(imagen);
   
    SDL_FreeSurface(imagen);

}

void Rectangle::initManagerElement(int gr)
{
	int w = base;
	int h = altura;
  
	int x = posicion->getX();
	int y = posicion->getY();


	e[0].x0 = x-gr;   
	e[0].y0 = y-gr;
	e[0].x1 = x+w+gr;
	e[0].y1 = y-gr;   
	
	e[1].x0 = x+w+gr;
	e[1].y0 = y-gr;
	e[1].x1 = x+w+gr;
	e[1].y1 = y+h+gr;

	e[2].x0 = x+w+gr;
	e[2].y0 = y+h+gr;
	e[2].x1 = x-gr;
	e[2].y1 = y+h+gr;

	e[3].x0 = x-gr;  
	e[3].y0 = y+h+gr;
	e[3].x1 = x-gr;
	e[3].y1 = y-gr;
	
}

void Rectangle::setManagerElement(SDL_Surface * auxSurface, int i)
{

		  e[i].dx = e[i].x1 - e[i].x0;
		  e[i].dy = e[i].y1 - e[i].y0;
		  e[i].ix = 2 * e[i].dx;
		  e[i].iy = 2 * e[i].dy;
		
		  if (e[i].dx < e[i].dy) 
			{
	  		  manager.swapPoints(&e[i]);
			  e[i].dx = -e[i].dx;
			  e[i].dy = -e[i].dy;
			  e[i].ix = -e[i].ix;
			  e[i].iy = -e[i].iy;
			}
    
		  if ( (e[i].dy <= -e[i].dx) || (e[i].dx < 0) ) manager.bhmLine3_5(auxSurface,&e[i]);
		  else manager.bhmLine1_7(auxSurface,&e[i]);

}



void Rectangle::setRectanglePoint(Point V1, int H, int W)
{
  v1 = V1;
  h = H;
  w = W;
}


void Rectangle::getRectanglePoint(Point& V1,int * H, int * W)
{
  V1 = v1;
  *H = h;
  *W = w;
}

void Rectangle::setRectangleColor(int R, int G, int B)
{
	
	r = R;
	g = G;
	b = B;
}





void Rectangle::hydrate(Element* elem) {
	
	char* idValue = NULL;
	int baseValue = -1;
	int alturaValue = -1;
	Point* posicionPoint = new Point();
	int rCLValue = -1;
	int gCLValue = -1;
	int bCLValue = -1;
	int rCFValue = -1;
	int gCFValue = -1;
	int bCFValue = -1;
	int lineThickness = -1;
	char* texId = NULL;
	Element auxElem;
	Attr auxAttr;
	int i=0;
	int j;


	//extraigo los subElementos con todos sus valores
	while(vectorListGetItem(elem->elems,i,&auxElem) != -1) {
		//Posicion
		if( strcmp("posicion", auxElem.name) == 0 ) {
			j=0;
			while(vectorListGetItem(auxElem.attrs,j,&auxAttr) != -1) {
				if(strcmp("x", auxAttr.name) == 0 )
					posicionPoint->setX(atoi(auxAttr.value));
				if(strcmp("y", auxAttr.name) == 0 )
					posicionPoint->setY(atoi(auxAttr.value));
				j++;
			}
		}

		//Colorlinea
		if( strcmp("colorlinea", auxElem.name) == 0 ) {
			j=0;
			while(vectorListGetItem(auxElem.attrs,j,&auxAttr) != -1) {
				if(strcmp("r", auxAttr.name) == 0 )
					rCLValue = atoi(auxAttr.value);
				if(strcmp("g", auxAttr.name) == 0 )
					gCLValue = atoi(auxAttr.value);
				if(strcmp("b", auxAttr.name) == 0 )
					bCLValue = atoi(auxAttr.value);
				j++;
			}
		}

		//ColorFigura
		if( strcmp("colorfigura", auxElem.name) == 0 ) {
			j=0;
			while(vectorListGetItem(auxElem.attrs,j,&auxAttr) != -1) {
				if(strcmp("r", auxAttr.name) == 0 )
					rCFValue = atoi(auxAttr.value);
				if(strcmp("g", auxAttr.name) == 0 )
					gCFValue = atoi(auxAttr.value);
				if(strcmp("b", auxAttr.name) == 0 )
					bCFValue = atoi(auxAttr.value);
				j++;
			}
		}

		//LineThickness
		if( strcmp("grosorlinea", auxElem.name) == 0 ) {
			j=0;
			while(vectorListGetItem(auxElem.attrs,j,&auxAttr) != -1) {
				if(strcmp("valor", auxAttr.name) == 0 )
					lineThickness = atoi(auxAttr.value);
				
				j++;
			}
		}

		//textura
		if( strcmp("textura", auxElem.name) == 0 ) {
			j=0;
			while(vectorListGetItem(auxElem.attrs,j,&auxAttr) != -1) {
				if(strcmp("id", auxAttr.name) == 0 )
					texId = auxAttr.value;
				j++;
			}
		}
		i++;
	}

	i=0;
	
	//extraigo los valores de los atributos de circulo
	while(vectorListGetItem(elem->attrs,i,&auxAttr) != -1) {
		if(strcmp("id", auxAttr.name) == 0 )
			idValue = auxAttr.value;
		if(strcmp("base", auxAttr.name) == 0 )
			baseValue = atoi(auxAttr.value);
		if(strcmp("altura", auxAttr.name) == 0 )
			alturaValue = atoi(auxAttr.value);

		i++;
	}

	this->setId(idValue);
	this->setBase(baseValue);
	this->setAltura(alturaValue);
	this->setPosicion(posicionPoint);
	this->setRColorLinea(rCLValue);
	this->setGColorLinea(gCLValue);
	this->setBColorLinea(bCLValue);
	this->setRColorFigura(rCFValue);
	this->setGColorFigura(gCFValue);
	this->setBColorFigura(bCFValue);
	this->setIdTextura(texId);
	this->setLineThickness(lineThickness);
}


int Rectangle::serialize(Element* elem) {
	Element posicion;
	Element colorlinea;
	Element colorfigura;
	Element textura;
	Attr attId;
	Attr attBase;
	Attr attAltura;
	Attr attX;
	Attr attY;
	Attr attRColorLinea;
	Attr attBColorLinea;
	Attr attGColorLinea;
	Attr attRColorFigura;
	Attr attGColorFigura;
	Attr attBColorFigura;
	Attr attIdTextura;

	//INICIO: inicializamos elementos y atributos.
	initAtt(&attId,255);
	initAtt(&attBase,255);
	initAtt(&attAltura,255);
	initAtt(&attX,255);
	initAtt(&attY,255);
	initAtt(&attRColorLinea,255);
	initAtt(&attGColorLinea,255);
	initAtt(&attBColorLinea,255);
	initAtt(&attRColorFigura,255);
	initAtt(&attGColorFigura,255);
	initAtt(&attBColorFigura,255);
	initAtt(&attIdTextura,255);
	initElement(&(*elem),255,255);
	initElement(&posicion,255,255);
	initElement(&colorlinea,255,255);
	initElement(&colorfigura,255,255);
	initElement(&textura,255,255);
	//FIN: inicializamos elementos y atributos.

	//INICIO: cargamos los nombres de los elementos.
	memset(elem->name,'\0',255);
	elem->name = "rectangulo";
	memset(posicion.name,'\0',255);
	posicion.name = "posicion";
	memset(colorlinea.name,'\0',255);
	colorlinea.name = "colorlinea";
	memset(colorfigura.name,'\0',255);
	colorfigura.name = "colorfigura";
	memset(textura.name,'\0',255);
	textura.name = "textura";
	//FIN: cargamos los nombres de los elementos.


	//INICIO: cargamos atributos de FIGURA.
	memset(attId.name,'\0',255);
	attId.name = "id";
	memset(attId.value,'\0',255);
	attId.value = this->getId();

	vectorListAddItem(&(elem->attrs),&attId,sizeof(attId));

	memset(attBase.name,'\0',255);
	attBase.name = "base";
	memset(attBase.value,'\0',255);
	string base = intToString(this->getBase());
	const char* baseChar = base.c_str();
	strcpy(attBase.value,baseChar);

	vectorListAddItem(&(elem->attrs),&attBase,sizeof(attBase));

	memset(attAltura.name,'\0',255);
	attAltura.name = "altura";
	memset(attAltura.value,'\0',255);
	string altura = intToString(this->getAltura());
	const char* alturaChar = altura.c_str();
	strcpy(attAltura.value,alturaChar);

	vectorListAddItem(&(elem->attrs),&attAltura,sizeof(attAltura));
	//FIN: cargamos atributos de FIGURA.



	//INICIO: cargamos atributos de POSICION.
	memset(attX.name,'\0',255);
	attX.name = "x";
	memset(attX.value,'\0',255);
	string xString = intToString(this->getPosicion()->getX());
	const char* xChar = xString.c_str();
	strcpy(attX.value,xChar);

	vectorListAddItem(&(posicion.attrs),&attX,sizeof(attX));

	memset(attY.name,'\0',255);
	attY.name = "y";
	memset(attY.value,'\0',255);
	string yString = intToString(this->getPosicion()->getY());
	const char* yChar = yString.c_str();
	strcpy(attY.value,yChar);

	vectorListAddItem(&(posicion.attrs),&attY,sizeof(attY));
	//FIN: cargamos atributos de POSICION.



	//INICIO: cargamos atributos de COLORLINEA.
	memset(attRColorLinea.name,'\0',255);
	attRColorLinea.name = "r";
	memset(attRColorLinea.value,'\0',255);
	string rColorLineaString = intToString(this->getRColorLinea());
	const char* rCLChar = rColorLineaString.c_str();
	strcpy(attRColorLinea.value,rCLChar);

	vectorListAddItem(&(colorlinea.attrs),&attRColorLinea,sizeof(attRColorLinea));

	memset(attGColorLinea.name,'\0',255);
	attGColorLinea.name = "g";
	memset(attGColorLinea.value,'\0',255);
	string gColorLineaString = intToString(this->getGColorLinea());
	const char* gCLChar = gColorLineaString.c_str();
	strcpy(attGColorLinea.value,gCLChar);

	vectorListAddItem(&(colorlinea.attrs),&attGColorLinea,sizeof(attGColorLinea));

	memset(attBColorLinea.name,'\0',255);
	attBColorLinea.name = "b";
	memset(attBColorLinea.value,'\0',255);
	string bColorLineaString = intToString(this->getBColorLinea());
	const char* bCLChar = bColorLineaString.c_str();
	strcpy(attBColorLinea.value,bCLChar);

	vectorListAddItem(&(colorlinea.attrs),&attBColorLinea,sizeof(attBColorLinea));
	//FIN: cargamos atributos de COLORLINEA.


	//INICIO: cargamos atributos de COLORFIGURA.
	memset(attRColorFigura.name,'\0',255);
	attRColorFigura.name = "r";
	memset(attRColorFigura.value,'\0',255);
	string rColorFiguraString = intToString(this->getRColorFigura());
	const char* rCFChar = rColorFiguraString.c_str();
	strcpy(attRColorFigura.value,rCFChar);

	vectorListAddItem(&(colorfigura.attrs),&attRColorFigura,sizeof(attRColorFigura));

	memset(attGColorFigura.name,'\0',255);
	attGColorFigura.name = "g";
	memset(attGColorFigura.value,'\0',255);
	string gColorFiguraString = intToString(this->getGColorFigura());
	const char* gCFChar = gColorFiguraString.c_str();
	strcpy(attGColorFigura.value,gCFChar);

	vectorListAddItem(&(colorfigura.attrs),&attGColorFigura,sizeof(attGColorFigura));

	memset(attBColorFigura.name,'\0',255);
	attBColorFigura.name = "b";
	memset(attBColorFigura.value,'\0',255);
	string bColorFiguraString = intToString(this->getBColorFigura());
	const char* bCFChar = bColorFiguraString.c_str();
	strcpy(attBColorFigura.value,bCFChar);

	
	vectorListAddItem(&(colorfigura.attrs),&attBColorFigura,sizeof(attBColorFigura));
	//FIN: cargamos atributos de COLORFIGURA.


	//INICIO: cargamos atributos de TEXTURA.	
	memset(attIdTextura.name,'\0',255);
	attIdTextura.name = "id";
	memset(attIdTextura.value,'\0',255);
	attIdTextura.value = this->getIdTextura();

	vectorListAddItem(&(textura.attrs),&attIdTextura,sizeof(attIdTextura));

	//FIN: cargamos atributos de TEXTURA.


	//INICIO: agregamos todos los elementos dentro de la figura.
	vectorListAddItem(&(elem->elems),&posicion,sizeof(posicion));
	vectorListAddItem(&(elem->elems),&colorlinea,sizeof(colorlinea));
	vectorListAddItem(&(elem->elems),&colorfigura,sizeof(colorfigura));
	vectorListAddItem(&(elem->elems),&textura,sizeof(textura));
	//FIN: agregamos todos los elementos dentro de la figura.

	return 0;

}



void Rectangle::setPosicion(Point* point) {
	this->posicion->setX(point->getX());
	this->posicion->setY(point->getY());
}

Point* Rectangle::getPosicion() {
	return this->posicion;
}

void Rectangle::fillColor(SDL_Surface *screen) {


	SDLDrawElement eAux;
	manager.bhmScanLineInit(screen,&eAux);

	for ( int i= 0; i < 4; i++) {
		manager.bhmScanLine(screen,e[i].x0,e[i].y0,e[i].x1,e[i].y1,&eAux);	
	}
	// ahora unimos el primer y el ultimo  punto
	//manager.bhmScanLine(screen,e[3].x0,e[3].y0,e[0].x1,e[0].y1,&eAux);	

	
	//Obetner el color de Figura en cascada
	Stage* stage = Stage::getInstance();
	int r = (this->getRColorFigura() != -1)? this->getRColorFigura() : stage->resolveShapeRColor();
	int g = (this->getGColorFigura() != -1)? this->getGColorFigura() : stage->resolveShapeGColor();
	int b = (this->getBColorFigura() != -1)? this->getBColorFigura() : stage->resolveShapeBColor();


	manager.setColor(screen,r,g,b);
	manager.bhmScanLineFill(screen,&eAux); // ESTE RELLENA ADENTRO

	//Obetner el color de linea en cascada
	int rl = (this->getRColorLinea() != -1)? this->getRColorLinea() : stage->resolveLineRColor();
	int gl = (this->getGColorLinea() != -1)? this->getGColorLinea() : stage->resolveLineGColor();
	int bl = (this->getBColorLinea() != -1)? this->getBColorLinea() : stage->resolveLineBColor();


	manager.setColor(screen,rl,gl,bl);


/*	int x0,y0,x1,y1,w1,h1;
	w1 = this->getBase();
	h1 = this->getAltura();

	x1 = (this->getPosicion()->getX()) + (w1/2);
	y1 = (this->getPosicion()->getY()) + (h1/2);
        for (x0=-800;x0<801;x0++) {
                for (y0=-600;y0<601;y0++) {
                        if (((sqrt((x1-x0)*(x1-x0)))<(w1/2)) && ((sqrt((y1-y0)*(y1-y0)))<(h1/2))) {
							manager.setearColor(screen,this->getRColorFigura(),this->getGColorFigura(),this->getBColorFigura());
					        manager.dibujarPunto(screen,x0,y0);
                        }
                }
        }
*/
}





void Rectangle::fillThickness(SDL_Surface *screen, int thickness) {
	Stage* stage = Stage::getInstance();
	for ( int gr=0 ; gr<thickness ; gr++) {
        initManagerElement(gr);
		for (int i = 0; i < 4; i++) {
			setManagerElement(screen,i);
		}
	}  
}









